//-----------------------------------------------------------------------
// <copyright file="TypeSystem.cs" company="Rhys Parry">
//    Copyright Rhys Parry 2009
//    This file is released under the Apache 2.0 License
//    This class is based on Matt Warren's class described in the blog
//    post:
//    http://blogs.msdn.com/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx
// </copyright>
//-----------------------------------------------------------------------
namespace Smarts.Core.Linq
{
    using System;
    using System.Collections;

    internal static class TypeSystem
    {
        internal static Type GetElementType(Type seqType)
        {
            var iEnumerable = FindIEnumerable(seqType);
            return iEnumerable == null ? seqType : iEnumerable.GetGenericArguments()[0];
        }

        private static Type FindIEnumerable(Type seqType)
        {
            if (seqType == null || seqType == typeof(string))
            {
                return null;
            }

            if (seqType.IsArray)
            {
                return typeof (IEnumerable).MakeGenericType(seqType.GetElementType());
            }

            if (seqType.IsGenericType)
            {
                foreach (var arg in seqType.GetGenericArguments())
                {
                    var iEnumerable = typeof(IEnumerable).MakeGenericType(arg);
                    if (iEnumerable.IsAssignableFrom(seqType))
                    {
                        return iEnumerable;
                    }
                }
            }

            var interfaces = seqType.GetInterfaces();
            if (interfaces != null && interfaces.Length > 0)
            {
                foreach (var type in interfaces)
                {
                    var iEnumerable = FindIEnumerable(type);
                    if (iEnumerable != null)
                    {
                        return iEnumerable;
                    }
                }
            }

            if (seqType.BaseType != null && seqType.BaseType != typeof(object))
            {
                return FindIEnumerable(seqType.BaseType);
            }

            return null;
        }
    }
}